home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / osrc.arc / UDP.C < prev    next >
Encoding:
C/C++ Source or Header  |  1989-03-19  |  7.2 KB  |  304 lines

  1. /* Send and receive User Datagram Protocol packets */
  2. #include "global.h"
  3. #include "mbuf.h"
  4. #include "netuser.h"
  5. #include "udp.h"
  6. #include "internet.h"
  7.  
  8. struct mbuf *htonudp(); 
  9. static struct udp_cb *lookup_udp();
  10. static int16 hash_udp();
  11.  
  12. /* Hash table for UDP structures */
  13. struct udp_cb *Udps[NUDP] = { NULLUDP} ;
  14. struct udp_stat Udp_stat;    /* Statistics */
  15.  
  16. /* Create a UDP control block for lsocket, so that we can queue
  17.  * incoming datagrams.
  18.  */
  19. struct udp_cb *
  20. open_udp(lsocket,r_upcall)
  21. struct socket *lsocket;
  22. void (*r_upcall)();
  23. {
  24.     register struct udp_cb *up;
  25.     int16 hval; 
  26.  
  27.     if((up = lookup_udp(lsocket)) != NULLUDP)
  28.         return up;    /* Already exists */
  29.     if((up = (struct udp_cb *)calloc(1,sizeof (struct udp_cb))) == NULLUDP){
  30.         Net_error = NO_SPACE;
  31.         return NULLUDP;
  32.     }
  33.     up->socket.address = lsocket->address;
  34.     up->socket.port = lsocket->port;
  35.     up->r_upcall = r_upcall;
  36.  
  37.     hval = hash_udp(lsocket);
  38.     up->next = Udps[hval];
  39.     if(up->next != NULLUDP)
  40.         up->next->prev = up;
  41.     Udps[hval] = up;
  42.     return up;
  43. }
  44.  
  45. /* Send a UDP datagram */
  46. int
  47. send_udp(lsocket,fsocket,tos,ttl,data,length,id,df)
  48. struct socket *lsocket;        /* Source socket */
  49. struct socket *fsocket;        /* Destination socket */
  50. char tos;            /* Type-of-service for IP */
  51. char ttl;            /* Time-to-live for IP */
  52. struct mbuf *data;        /* Data field, if any */
  53. int16 length;            /* Length of data field */
  54. int16 id;            /* Optional ID field for IP */
  55. char df;            /* Don't Fragment flag for IP */
  56. {
  57.     struct mbuf *bp;
  58.     struct pseudo_header ph;
  59.     struct udp udp;
  60.  
  61.     length = UDPHDR;
  62.     if(data != NULLBUF)
  63.         length += len_mbuf(data);
  64.  
  65.     udp.source = lsocket->port;
  66.     udp.dest = fsocket->port;
  67.     udp.length = length;
  68.  
  69.     /* Create IP pseudo-header, compute checksum and send it */
  70.     ph.length = length;
  71.     ph.source = lsocket->address;
  72.     ph.dest = fsocket->address;
  73.     ph.protocol = UDP_PTCL;
  74.  
  75.     if((bp = htonudp(&udp,data,&ph)) == NULLBUF){
  76.         Net_error = NO_SPACE;
  77.         free_p(data);
  78.         return 0;
  79.     }
  80.     Udp_stat.sent++;
  81.     ip_send(lsocket->address,fsocket->address,UDP_PTCL,tos,ttl,bp,length,id,df);
  82.     return length;
  83. }
  84. /* Accept a waiting datagram, if available. Returns length of datagram */
  85. int
  86. recv_udp(up,fsocket,bp)
  87. register struct udp_cb *up;
  88. struct socket *fsocket;        /* Place to stash incoming socket */
  89. struct mbuf **bp;        /* Place to stash data packet */
  90. {
  91.     struct socket *sp;
  92.     struct mbuf *buf;
  93.     int16 length;
  94.  
  95.     if(up == NULLUDP){
  96.         Net_error = NO_CONN;
  97.         return -1;
  98.     }
  99.     if(up->rcvcnt == 0){
  100.         Net_error = WOULDBLK;
  101.         return -1;
  102.     }
  103.     buf = dequeue(&up->rcvq);
  104.     up->rcvcnt--;
  105.  
  106.     sp = (struct socket *)buf->data;
  107.     /* Fill in the user's foreign socket structure, if given */
  108.     if(fsocket != NULLSOCK){
  109.         fsocket->address = sp->address;
  110.         fsocket->port = sp->port;
  111.     }
  112.     /* Strip socket header and hand data to user */
  113.     pullup(&buf,NULLCHAR,sizeof(struct socket));
  114.     length = len_mbuf(buf);
  115.     if(bp != (struct mbuf **)NULL)
  116.         *bp = buf;
  117.     else
  118.         free_p(buf);
  119.     return length;
  120. }
  121. /* Delete a UDP control block */
  122. int
  123. del_udp(up)
  124. struct udp_cb *up;
  125. {
  126.     struct mbuf *bp;
  127.     int16 hval;
  128.  
  129.     if(up == NULLUDP){
  130.         Net_error = INVALID;
  131.         return -1;
  132.     }        
  133.     /* Get rid of any pending packets */
  134.     while(up->rcvcnt != 0){
  135.         bp = up->rcvq;
  136.         up->rcvq = up->rcvq->anext;
  137.         free_p(bp);
  138.         up->rcvcnt--;
  139.     }
  140.     hval = hash_udp(&up->socket);
  141.     if(up->prev == NULLUDP)
  142.         Udps[hval] = up->next;        /* First on list */
  143.     else
  144.         up->prev->next = up->next;
  145.     if(up->next != NULLUDP)
  146.         up->next->prev = up->prev;
  147.  
  148.     free((char *)up);
  149.     return 0;
  150. }
  151. /* Process an incoming UDP datagram */
  152. void
  153. udp_input(bp,protocol,source,dest,tos,length,rxbroadcast)
  154. struct mbuf *bp;    /* UDP header and data */
  155. char protocol;        /* Should always be 17 */
  156. int32 source;        /* Source IP address */
  157. int32 dest;        /* Dest IP address */
  158. char tos;
  159. int16 length;
  160. char rxbroadcast;    /* The only protocol that accepts 'em */
  161. {
  162.     struct pseudo_header ph;
  163.     struct udp udp;
  164.     struct udp_cb *up;
  165.     struct socket lsocket;
  166.     struct socket *fsocket;
  167.     struct mbuf *packet;
  168.     int ckfail = 0;
  169.  
  170.     if(bp == NULLBUF)
  171.         return;
  172.  
  173.     Udp_stat.rcvd++;
  174.  
  175.     /* Create pseudo-header and verify checksum */
  176.     ph.source = source;
  177.     ph.dest = dest;
  178.     ph.protocol = protocol;
  179.     ph.length = length;
  180.  
  181.     if(cksum(&ph,bp,length) != 0)
  182.         /* Checksum apparently failed, note for later */
  183.         ckfail++;
  184.  
  185.     /* Extract UDP header in host order */
  186.     ntohudp(&udp,&bp);
  187.  
  188.     /* If the checksum field is zero, then ignore a checksum error.
  189.      * I think this is dangerously wrong, but it is in the spec.
  190.      */
  191.     if(ckfail && udp.checksum != 0){
  192.         Udp_stat.cksum++;
  193.         free_p(bp);
  194.         return;
  195.     }
  196.     /* If this was a broadcast packet, pretend it was sent to us */
  197.     if(rxbroadcast){
  198.         lsocket.address = Ip_addr;
  199.         Udp_stat.bdcsts++;
  200.     } else
  201.         lsocket.address = dest;
  202.  
  203.     lsocket.port = udp.dest;
  204.     /* See if there's somebody around to read it */
  205.     if((up = lookup_udp(&lsocket)) == NULLUDP){
  206.         /* Nope, toss it on the floor */
  207.         Udp_stat.unknown++;
  208.         free_p(bp);
  209.         return;
  210.     }
  211.     /* Create space for the foreign socket info */
  212.     if((packet = pushdown(bp,sizeof(struct socket))) == NULLBUF){
  213.         /* No space, drop whole packet */
  214.         free_p(bp);
  215.         return;
  216.     }
  217.     fsocket = (struct socket *)packet->data;
  218.     fsocket->address = source;
  219.     fsocket->port = udp.source;
  220.  
  221.     /* Queue it */
  222.     enqueue(&up->rcvq,packet);
  223.     up->rcvcnt++;
  224.     if(up->r_upcall)
  225.         (*up->r_upcall)(up,up->rcvcnt);
  226. }
  227. /* Look up UDP socket, return control block pointer or NULLUDP if nonexistant */
  228. static
  229. struct udp_cb *
  230. lookup_udp(socket)
  231. struct socket *socket;
  232. {
  233.     register struct udp_cb *up;
  234.  
  235.     up = Udps[hash_udp(socket)];
  236.     while(up != NULLUDP){
  237.         if(memcmp((char *)socket,(char *)&up->socket,sizeof(struct socket)) == 0)
  238.             break;
  239.         up = up->next;
  240.     }
  241.     return up;
  242. }
  243.  
  244. /* Hash a UDP socket (address and port) structure */
  245. static
  246. int16
  247. hash_udp(socket)
  248. struct socket *socket;
  249. {
  250.     register unsigned int hval;
  251.  
  252.     /* Compute hash function on socket structure */
  253.     hval = hiword(socket->address);
  254.     hval ^= loword(socket->address);
  255.     hval ^= socket->port;
  256.     return hval % NUDP;
  257. }
  258. /* Convert UDP header in internal format to an mbuf in external format */
  259. struct mbuf *
  260. htonudp(udp,data,ph)
  261. struct udp *udp;
  262. struct mbuf *data;
  263. struct pseudo_header *ph;
  264. {
  265.     struct mbuf *bp;
  266.     register char *cp;
  267.     int16 checksum;
  268.  
  269.     /* Allocate UDP protocol header and fill it in */
  270.     if((bp = pushdown(data,UDPHDR)) == NULLBUF)
  271.         return NULLBUF;
  272.  
  273.     cp = bp->data;
  274.     cp = put16(cp,udp->source);    /* Source port */
  275.     cp = put16(cp,udp->dest);    /* Destination port */
  276.     cp = put16(cp,udp->length);    /* Length */
  277.     *cp++ = 0;            /* Clear checksum */
  278.     *cp-- = 0;
  279.  
  280.     /* All zeros and all ones is equivalent in one's complement arithmetic;
  281.      * the spec requires us to change zeros into ones to distinguish an
  282.       * all-zero checksum from no checksum at all
  283.      */
  284.     if((checksum = cksum(ph,bp,ph->length)) == 0)
  285.         checksum = 0xffffffff;
  286.     put16(cp,checksum);
  287.     return bp;
  288. }
  289. /* Convert UDP header in mbuf to internal structure */
  290. ntohudp(udp,bpp)
  291. struct udp *udp;
  292. struct mbuf **bpp;
  293. {
  294.     char udpbuf[UDPHDR];
  295.  
  296.     if(pullup(bpp,udpbuf,UDPHDR) != UDPHDR)
  297.         return -1;
  298.     udp->source = get16(&udpbuf[0]);
  299.     udp->dest = get16(&udpbuf[2]);
  300.     udp->length = get16(&udpbuf[4]);
  301.     udp->checksum = get16(&udpbuf[6]);
  302.     return 0;
  303. }
  304.